<template>
  <div class="webrtc-box">
    <el-row class="video-box" type="flex" justify="space-around">
      <el-card class="box-card">
        <div slot="header" class="clearfix">
          <span>本地视频流</span>
        </div>
        <div>
          <video ref="localVideo" autoplay muted playsinline></video>
        </div>
      </el-card>
      <el-card class="box-card">
        <div slot="header" class="clearfix">
          <span>远程视频流</span>
          <el-button style="float: right; padding: 3px 0" type="text"
            >在线人数:{{ numClients }}</el-button
          >
        </div>
        <div>
          <video ref="remoteVideo" autoplay playsinline></video>
        </div>
      </el-card>
    </el-row>
    <div>
      <InputText :userName="userName" :roomName="roomName"></InputText>
    </div>
  </div>
</template>

<script>
import InputText from "./InputText";
export default {
  components: { InputText },
  data() {
    return {
      localStream: null, // 本地媒体流

      isInitiator: false, // 是否为创始者

      roomName: "", // 房间名称

      userName: "", // 用户名称

      isChannelReady: false, // 通道是否准备就绪

      numClients: null, // 在线人数

      pc: null, // RTCPeerConnection，本地端机器与远端机器的一条对等连接

      pcConfiguration: {
        // coturn配置供 RTCPeerConnection 使用
        iceServers: [
          { url: "stun:stun.l.google.com:19302" }, // 谷歌的公共服务
          {
            urls: "turn:wzeros.cn",
            username: "wzeros",
            credential: "123456",
          },
        ],
      },

      remoteStream: null, // 远程媒体流
    };
  },
  created() {
    this.init();
  },
  mounted() {
    this.getUserMedia();
  },
  beforeDestroy() {
    this.sendMessage("leave");
  },
  methods: {
    init() {
      this.roomName = this.$route.query.roomName;
      this.userName = this.$route.query.userName;
    },
    // 获取本地用户媒体流
    isgetUserMedia(constrains) {
      if (navigator.mediaDevices.getUserMedia) {
        //最新标准API
        return navigator.mediaDevices.getUserMedia(constrains);
        // .then(success)
        // .catch(error);
      } else if (navigator.webkitGetUserMedia) {
        //webkit内核浏览器
        return navigator.webkitGetUserMedia(constrains);
        // .then(success)
        // .catch(error);
      } else if (navigator.mozGetUserMedia) {
        //Firefox浏览器
        return navagator.mozGetUserMedia(constrains);
        // .then(success)
        // .catch(error);
      } else if (navigator.getUserMedia) {
        //旧版API
        return navigator.getUserMedia(constrains);
        // .then(success)
        // .catch(error);
      }
    },
    getUserMedia() {
      // Socket IO 存在 && 未连接到服务器
      if (this.$socket != null && !this.$socket.connected) {
        this.$socket.connect();
      }
      // navigator.mediaDevices.getUserMedia 3个工作域：http://localhost/ 、HTTPS://或file://，否则会是undefined

      this.isgetUserMedia({
        audio: false,
        video: true,
      })
        .then((stream) => {
          this.$lib.logInfo("获取本地用户媒体流");
          // 赋值本地媒体流
          this.localStream = stream;
          // 在浏览器中进行展示
          this.$refs.localVideo.srcObject = stream;
          // 试图创建或加入Socket IO的房间
          this.createOrJoinRoom();
          console.log(stream);
        })
        .catch((err) => {
          this.$lib.logError(
            "获取navigator.mediaDevices.getUserMedia()失败，错误原因如下："
          );
          this.$lib.logObj(err);
          alert(
            "获取navigator.mediaDevices.getUserMedia()失败,请使用Chrome 新版浏览器！"
          );
        });
    },
    // 发送消息给 Socket IO 服务器
    sendMessage(msg) {
      this.$socket.emit("message", msg);
    },
    // 试图创建或加入Socket IO的房间
    createOrJoinRoom() {
      this.$lib.logInfo("试图创建或加入Socket IO 的房间：" + this.roomName);
      this.$socket.emit("create or join", this.roomName);
    },
    // 创建本地端机器与远端机器的一条对等连接
    createPeerConnection() {
      try {
        this.$lib.logInfo("创建 RTCPeerConnection");
        let PeerConnection =
          window.RTCPeerConnection ||
          window.mozRTCPeerConnection ||
          window.webkitRTCPeerConnection;
        this.pc = new PeerConnection(this.pcConfiguration);
        this.pc.onicecandidate = this.handleIceCandidate;
        this.pc.onaddstream = this.handleRemoteStreamAdded;
        this.pc.onremovestream = this.handleRemoteStreamRemoved;

        this.$lib.logInfo("增加本地媒体流");
        this.pc.addStream(this.localStream);
      } catch (e) {
        this.$lib.logError("创建 RTCPeerConnection 出错，错误原因如下");
        this.$lib.logObj(e.message);
        return;
      }
    },
    // 事件触发器
    // 只要本地代理ICE 需要通过信令服务器传递信息给其他对等端时就会触发
    // 功能说明地址：https://developer.mozilla.org/zh-CN/docs/Web/API/RTCPeerConnection/onicecandidate
    handleIceCandidate(event) {
      this.$lib.logInfo("触发 icecandidate 事件，事件内容如下");
      this.$lib.logObj(event);

      if (event.candidate) {
        let _msg = {
          type: "candidate",
          label: event.candidate.sdpMLineIndex,
          id: event.candidate.sdpMid,
          candidate: event.candidate.candidate,
        };

        this.sendMessage(_msg);
      } else {
        this.$lib.logInfo("End of candidates");
      }
    },
    // 处理远程流添加
    handleRemoteStreamAdded(event) {
      this.$lib.logInfo("处理远程媒体流添加");

      // 赋值远程媒体流
      this.remoteStream = event.stream;
      // 展示远程媒体流
      this.$refs.remoteVideo.srcObject = this.remoteStream;
    },
    // 处理远程流撤掉
    handleRemoteStreamRemoved(event) {
      this.$lib.logInfo("Remote stream removed. Event: ");
      this.$lib.logObj(event);
    },
    // 创建 offer
    createOffer() {
      this.$lib.logInfo("发送offer给远程的伙伴");

      this.pc.createOffer(
        (sessionDescription) => {
          this.$lib.logInfo("设置本地描述，描述内容如下：");
          this.$lib.logObj(sessionDescription);
          this.pc.setLocalDescription(sessionDescription);

          // 通过Signal Server 发送(offer) sessionDescription 到远程伙伴
          this.sendMessage(sessionDescription);
        },
        (event) => {
          this.$lib.logError("createOffer()出错，错误原因如下：");
          this.$lib.logObj(event);
        }
      );
    },
    // 创建 answer
    createAnswer() { 
      this.$lib.logInfo("发送answer给远程的创建者");

      this.pc.createAnswer().then(
        (sessionDescription) => {
          this.$lib.logInfo("设置会话描述，描述内容如下：");
          this.$lib.logObj(sessionDescription);
          this.pc.setLocalDescription(sessionDescription);

          // 通过Signal Server 发送(answer) sessionDescription 到远程的创建者
          this.sendMessage(sessionDescription);
        },
        (error) => {
          this.$lib.logError("创建会话描述出错，错误原因如下：");
          this.$lib.logObj(error);
        }
      );
    },
    // 关闭通信
    leave() {
      if (this.remoteStream !== null) {
        this.$refs.remoteVideo.srcObject = null;
        this.remoteStream = null;
      }

      if (this.localStream !== null) {
        this.$refs.localVideo.srcObject = null;
        this.localStream = null;
      }

      if (this.pc !== null) {
        this.pc.close();
        this.pc = null;
      }
    },
    notify(data) {
      this.$notify({
        title: "提示",
        message: data,
        position: "top-left",
      });
    },
  },

  sockets: {
    connect() {
      this.$lib.logSuccess("连接socket io服务器成功");
    },
    message(msg) {
      this.$lib.logInfo("接收到服务端的消息，消息如下：");
      this.$lib.logObj(msg);
      if (msg.type) {
        switch (msg.type) {
          case "offer": // 加入者接收到创建者的offer
            // 创建本地端机器与远端机器的一条对等连接
            this.createPeerConnection();
            // 设置远程会话描述
            this.pc.setRemoteDescription(new RTCSessionDescription(msg));
            // 给创建者回复
            this.createAnswer();
            break;
          case "answer": // 创建者接收到加入者的answer
            // 设置远程会话描述
            this.pc.setRemoteDescription(new RTCSessionDescription(msg));
            break;
          case "candidate": // candidate处理
            this.pc.addIceCandidate(
              new RTCIceCandidate({
                sdpMLineIndex: msg.label,
                candidate: msg.candidate,
              })
            );
            break;
          case "leave": // 离开通信
            this.leave();
            break;
          default:
            break;
        }
      }
    },
    created(room) {
      // this.$lib.logInfo("您是房间：" + room + " 的创建者");
      this.notify("您是房间：" + room + " 的创建者");
      // 赋值创建者标志
      this.isInitiator = true;
    },
    joined(room) {
      // this.$lib.logInfo("房间：" + room + " 已经加入成功");
      this.notify("房间：" + room + " 已经加入成功");
      // 加入者，设定通道准备就绪
      this.isChannelReady = true;
    },
    numClients(data) {
      //在线人数
      this.numClients = data;
    },
    ready(room) {
      // this.$lib.logInfo("房间：" + room + " 新的用户已经加入成功");
      this.notify("房间：" + room + " 新的用户已经加入成功");
      // 创建者 | 加入者，设定通道准备就绪
      this.isChannelReady = true;

      // 创建者
      if (this.isInitiator) {
        // 创建本地端机器与远端机器的一条对等连接
        this.createPeerConnection();
        // 创建 offer
        this.createOffer();
      }
    },
    full(room) {
      // this.$lib.logInfo("房间：" + room + " 已经满员了");
      // window.location.reload()
    },
  },
};
</script>
<style scoped>
video {
  max-width: 100%;
  width: 217px;
  height: 162px;
  border: 1px solid;
}

.webrtc-box {
  /* box-sizing: border-box;
  display: flex;
  justify-content: center; */
}
.webrtc-box .video-box {
}
.webrtc-box .box-card {
}
</style>
